﻿using System.ComponentModel;
using K9Nano.Dependency;
using K9Nano.Exceptions;
using K9Nano.Extensions;
using K9Nano.Settings;

namespace K9Nano.Application.Setting;

public abstract class SettingGroupEditHandlerBase : ISettingGroupEditHandler
{
    protected readonly ISettingDefinitionManager SettingDefinitionManager;

    protected readonly ISettingManager SettingManager;

    protected SettingGroupEditHandlerBase(ISettingDefinitionManager settingDefinitionManager, ISettingManager settingManager)
    {
        SettingDefinitionManager = settingDefinitionManager;
        SettingManager = settingManager;
    }

    public virtual async Task<SettingEditModelGroup> GetAsync(CancellationToken cancellation = default)
    {
        var thisType = GetType();
        if (!thisType.TryGetCustomAttribute<ServiceKeyNameAttribute>(false, out var nameAttr))
        {
            throw new Exception($"{thisType.FullName}未声明ServiceKeyAttribute");
        }
        if (!thisType.TryGetCustomAttribute<DescriptionAttribute>(false, out var descAttr))
        {
            throw new Exception($"{thisType.FullName}未声明DescriptionAttribute");
        }

        var group = new SettingEditModelGroup
        {
            Name = nameAttr!.Key,
            DisplayName = descAttr!.Description,
            Settings = await GetSettingModelsAsync(cancellation)
        };

        return group;
    }

    protected async Task<SettingEditModel> GetSettingEditModelAsync(string settingName, CancellationToken cancellation)
    {
        var definition = SettingDefinitionManager.GetSettingDefinition(settingName);
        if (definition is null)
        {
            throw new FriendlyException($"设置项未定义：{settingName}");
        }
        var value = await SettingManager.GetSettingValueAsync(settingName, cancellation);

        return new SettingEditModel
        {
            Name = settingName,
            DisplayName = definition.DisplayName,
            Description = definition.Description,
            Options = definition.Options,
            Value = value
        };
    }

    public virtual async Task SaveAsync(IReadOnlyList<SettingChangeInput> settings, CancellationToken cancellation = default)
    {
        await ValidateAsync(settings, cancellation);

        foreach (var input in settings)
        {
            await SettingManager.ChangeSettingAsync(input.Name, input.Value!, cancellation);
        }
    }

    protected abstract Task ValidateAsync(IReadOnlyList<SettingChangeInput> settings, CancellationToken cancellation);

    protected abstract Task<IReadOnlyList<SettingEditModel>> GetSettingModelsAsync(CancellationToken cancellation);

}